import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_wechat/constants.dart';
import 'package:flutter_wechat/main.dart';
import 'package:lpinyin/lpinyin.dart';

class AddressListPage extends StatefulWidget {
  final PopupMenuItemSelected<String> onSelected;


  const AddressListPage({this.onSelected, Key key}) : super(key: key);

  @override
  _AddressListPageState createState() => _AddressListPageState();
}

class _AddressListPageState extends State<AddressListPage> {
  List<AddressItemModel> _listData = _addressMockData();

  @override
  void initState() {
    super.initState();
    _listData.insert(0, AddressItemModel(name: "公众号"));
    _listData.insert(0, AddressItemModel(name: "标签"));
    _listData.insert(0, AddressItemModel(name: "群聊"));
    _listData.insert(0, AddressItemModel(name: "新的朋友"));
  }

  final ScrollController _scrollController = ScrollController();
  String _tag = "";
  bool _isShow = false;

  @override
  Widget build(BuildContext context) {
    final query = MediaQuery.of(context);
    final _h = query.size.height - (kToolbarHeight * 2) - 15;
    return Scaffold(
      appBar: getMyAppBar(onSelected: widget.onSelected, title: "通讯录"),
      body: Container(
        color: Color(0xffEDEDED),
        alignment: Alignment.center,
        child: Stack(
          alignment: Alignment.topRight,
          children: <Widget>[
            ListView.separated(
                controller: _scrollController,
                itemBuilder: (context, index) => (index == _listData.length)
                    ? Container(
                        alignment: Alignment.center,
                        height: 60.0,
                        child: Text(
                          "${_listData.where((i) => !i.isIndex).length - 4}位联系人",
                          style: TextStyle(fontSize: 18.0, color: Colors.grey),
                        ),
                      )
                    : _AddressItemWidget(_listData[index], index),
                separatorBuilder: (context, index) => Row(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: <Widget>[
                        Container(
                          height: 0.4,
                          width: query.size.width * 0.8,
                          color: Colors.grey[300],
                        ),
                      ],
                    ),
                itemCount: _listData.length + 1),
            SingleChildScrollView(
              child: IndexBar(
                  onTouch: _onTouch,
                  onEnd: _onEnd,
                  onTapUp: _onTapUp,
                  itemHeight: _h ~/ 28,
                  width: 25,
                  touchDownColor: Colors.black26,
                  textStyle:
                      const TextStyle(fontSize: 14.0, color: Color(0xFF666666)),
                  touchDownTextStyle:
                      const TextStyle(fontSize: 14.0, color: Colors.black)),
            ),
            Container(
              height: double.maxFinite,
              width: double.maxFinite,
              alignment: Alignment.center,
              child: _ShowIndexWidget(tag: _tag, isShow: _isShow),
            ),
          ],
        ),
      ),
    );
  }

  void _onEnd() {
    setState(() {
      _isShow = false;
    });
  }

  void _onTouch(IndexBarDetails model) {
    double offset = getOffset(model);
    setState(() {
      _tag = model.tag;
      _isShow = true;
      if(offset > 0) {
        _scrollController.animateTo(offset,
            duration: Duration(milliseconds: 200), curve: Curves.bounceIn);
      }
    });
  }

  double getOffset(IndexBarDetails model) {
    double range = 0.0;
    int index = _listData.indexWhere((m) => m.isIndex && m.name == model.tag);
    if(index == -1) return -1;

    for (var m in _listData) {
      if (m.isIndex) {
        if (m.name == model.tag) {
          break;
        }
        range += 32.0;
      } else {
        range += 58.0;
        range += 0.6;
      }
    }
    return range;
  }

  void _onTapUp() {
    if(_isShow) {
      setState(() {
        _isShow = false;
      });
    }
  }
}

class _ShowIndexWidget extends StatelessWidget {
  final bool isShow;
  final String tag;

  const _ShowIndexWidget({this.isShow, this.tag});

  @override
  Widget build(BuildContext context) {
    return Offstage(
      offstage: !isShow,
      child: Container(
        alignment: Alignment.center,
        height: 80.0,
        width: 80.0,
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(5.0), color: Colors.black45),
        child: Text(
          tag,
          style: TextStyle(fontSize: 50.0, color: Colors.white),
        ),
      ),
    );
  }
}

class _AddressItemWidget extends StatelessWidget {
  final AddressItemModel model;
  final int index;

  const _AddressItemWidget(this.model, this.index);

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.centerLeft,
      height: model.isIndex ? 32.0 : 58.0,
      padding: EdgeInsets.symmetric(horizontal: 18.0, vertical: 5.0),
      color: model.isIndex ? Color(0xffEDEDED) : Colors.white,
      child: model.isIndex
          ? Text(model.name, style: TextStyle(color: Colors.grey))
          : Row(
              children: <Widget>[
                getHeadImg(model.name),
                const SizedBox(width: 15.0),
                Text(model.name, style: TextStyle(fontSize: 16.0)),
              ],
            ),
    );
  }

  Widget getHeadImg(String name) {
    Widget widget = Container(
      width: 45.0,
      height: 45.0,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(5.0),
        color: Colors.blue[100 * ((index + 1) % 5)],
      ),
    );

    double size = 43.0;
    switch (name) {
      case "新的朋友":
        widget = Container(
          width: 45.0,
          height: 45.0,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(5.0),
            color: Colors.orange,
          ),
          child: Icon(Icons.person_add, color: Colors.white),
        );
        break;

      case "群聊":
        widget = Container(
          width: 45.0,
          height: 45.0,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(5.0),
              color: Colors.green
          ),
          child: Icon(Icons.people, color: Colors.white),
        );
        break;

      case "标签":
        widget = Container(
          width: 45.0,
          height: 45.0,
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(5.0),
              color: Colors.blue
          ),
          child: Icon(Icons.flag, color: Colors.white),
        );
        break;

      case "公众号":
        widget = Container(
          width: 45.0,
          height: 45.0,
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(5.0),
              color: Colors.blue
          ),
          child: Icon(Icons.person, color: Colors.white),
        );
        break;
    }

    return widget;
  }
}

List<AddressItemModel> _addressMockData() {
  final _list = _addressMockData0();
  Map<String, List<AddressItemModel>> map = groupBy<AddressItemModel, String>(
      _list, (i) => i.shortPinYin[0].toUpperCase());
  var list = map.keys.toList();
  list.sort();
  List<AddressItemModel> _newList = [];
  list.forEach((index) {
    _newList.add(AddressItemModel(name: index, isIndex: true));
    map[index].sort((m1, m2) => m1.shortPinYin.compareTo(m2.shortPinYin));
    map[index].forEach((model) {
      _newList.add(model);
    });
  });
  return _newList;
}

List<AddressItemModel> _addressMockData0() {
  return <AddressItemModel>[
    AddressItemModel(name: "江德福"),
    AddressItemModel(name: "校长"),
    AddressItemModel(name: "安杰"),
    AddressItemModel(name: "老丁"),
    AddressItemModel(name: "江德华"),
    AddressItemModel(name: "江亚菲"),
    AddressItemModel(name: "江亚宁"),
    AddressItemModel(name: "江卫国"),
    AddressItemModel(name: "江卫东"),
    AddressItemModel(name: "江卫民"),
    AddressItemModel(name: "王海洋"),
    AddressItemModel(name: "王海洋"),
    AddressItemModel(name: "欧阳懿"),
    AddressItemModel(name: "安欣"),
    AddressItemModel(name: "安泰"),
    AddressItemModel(name: "欧阳安然"),
    AddressItemModel(name: "欧阳安诺"),
    AddressItemModel(name: "阿甘"),
    AddressItemModel(name: "许三多"),
    AddressItemModel(name: "李云龙"),
    AddressItemModel(name: "魏和尚"),
    AddressItemModel(name: "赵刚"),
    AddressItemModel(name: "楚云飞"),
    AddressItemModel(name: "李达康"),
    AddressItemModel(name: "侯亮平"),
    AddressItemModel(name: "冷锋"),
    AddressItemModel(name: "托尔"),
    AddressItemModel(name: "巴基"),
  ];
}

class AddressItemModel {
  final String name;
  final String img;
  final bool isIndex;
  String shortPinYin;

  AddressItemModel({this.name, this.img = "", this.isIndex = false})
      : shortPinYin = PinyinHelper.getShortPinyin(name);

  @override
  String toString() {
    return 'AddressItemModel{name: $name, img: $img, isIndex: $isIndex, shortPinYin: $shortPinYin}';
  }
}

/// IndexBar touch callback IndexModel.
typedef void IndexBarTouchCallback(IndexBarDetails model);

/// IndexModel.
class IndexBarDetails {
  String tag; //current touch tag.
  int position; //current touch position.
  bool isTouchDown; //is touch down.

  IndexBarDetails({this.tag, this.position, this.isTouchDown});
}

///Default Index data.
const List<String> INDEX_DATA_DEF = const [
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
  "G",
  "H",
  "I",
  "J",
  "K",
  "L",
  "M",
  "N",
  "O",
  "P",
  "Q",
  "R",
  "S",
  "T",
  "U",
  "V",
  "W",
  "X",
  "Y",
  "Z",
  "#"
];

/// IndexBar.
class IndexBar extends StatefulWidget {
  IndexBar(
      {Key key,
      this.data: INDEX_DATA_DEF,
      @required this.onTouch,
      this.onTapUp,
      this.onEnd,
      this.width: 30,
      this.itemHeight: 16,
      this.color = Colors.transparent,
      this.textStyle =
          const TextStyle(fontSize: 12.0, color: Color(0xFF666666)),
      this.touchDownColor = const Color(0xffeeeeee),
      this.touchDownTextStyle =
          const TextStyle(fontSize: 12.0, color: Colors.black)});

  /// index data.
  final List<String> data;

  /// IndexBar width(def:30).
  final int width;

  /// IndexBar item height(def:16).
  final int itemHeight;

  /// Background color
  final Color color;

  /// IndexBar touch down color.
  final Color touchDownColor;

  /// IndexBar text style.
  final TextStyle textStyle;

  final TextStyle touchDownTextStyle;

  /// Item touch callback.
  final IndexBarTouchCallback onTouch;

  final VoidCallback onEnd;

  final VoidCallback onTapUp;

  @override
  _SuspensionListViewIndexBarState createState() =>
      _SuspensionListViewIndexBarState();
}

class _SuspensionListViewIndexBarState extends State<IndexBar> {
  bool _isTouchDown = false;

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      color: _isTouchDown ? widget.touchDownColor : widget.color,
      width: widget.width.toDouble(),
      child: _IndexBar(
        data: widget.data,
        width: widget.width,
        itemHeight: widget.itemHeight,
        textStyle: widget.textStyle,
        touchDownTextStyle: widget.touchDownTextStyle,
        onEnd: widget.onEnd,
        onTapUp: widget.onTapUp,
        onTouch: (details) {
          if (widget.onTouch != null) {
            if (_isTouchDown != details.isTouchDown) {
              setState(() {
                _isTouchDown = details.isTouchDown;
              });
            }
            widget.onTouch(details);
          }
        },
      ),
    );
  }
}

/// Base IndexBar.
class _IndexBar extends StatefulWidget {
  /// index data.
  final List<String> data;

  /// IndexBar width(def:30).
  final int width;

  /// IndexBar item height(def:16).
  final int itemHeight;

  /// IndexBar text style.
  final TextStyle textStyle;

  final TextStyle touchDownTextStyle;

  /// Item touch callback.
  final IndexBarTouchCallback onTouch;

  final VoidCallback onEnd;

  final VoidCallback onTapUp;

  _IndexBar(
      {Key key,
      this.data: INDEX_DATA_DEF,
      @required this.onTouch,
      this.width: 30,
      this.itemHeight: 16,
      this.textStyle,
      this.touchDownTextStyle,
      this.onEnd,
      this.onTapUp})
      : assert(onTouch != null),
        super(key: key);

  @override
  _IndexBarState createState() => _IndexBarState();
}

class _IndexBarState extends State<_IndexBar> {
  List<int> _indexSectionList = new List();
  int _widgetTop = -1;
  int _lastIndex = 0;
  bool _widgetTopChange = false;
  bool _isTouchDown = false;
  IndexBarDetails _indexModel = new IndexBarDetails();

  /// get index.
  int _getIndex(int offset) {
    for (int i = 0, length = _indexSectionList.length; i < length - 1; i++) {
      int a = _indexSectionList[i];
      int b = _indexSectionList[i + 1];
      if (offset >= a && offset < b) {
        return i;
      }
    }
    return -1;
  }

  void _init() {
    _widgetTopChange = true;
    _indexSectionList.clear();
    _indexSectionList.add(0);
    int tempHeight = 0;
    widget.data?.forEach((value) {
      tempHeight = tempHeight + widget.itemHeight;
      _indexSectionList.add(tempHeight);
    });
  }

  _triggerTouchEvent() {
    if (widget.onTouch != null) {
      widget.onTouch(_indexModel);
    }
  }

  @override
  Widget build(BuildContext context) {
    TextStyle _style = widget.textStyle;
    if (_indexModel.isTouchDown == true) {
      _style = widget.touchDownTextStyle;
    }
    _init();

    List<Widget> children = new List();
    widget.data.forEach((v) {
      children.add(new SizedBox(
        width: widget.width.toDouble(),
        height: widget.itemHeight.toDouble(),
        child: new Text(v, textAlign: TextAlign.center, style: _style),
      ));
    });

    return GestureDetector(
      onVerticalDragDown: (DragDownDetails details) {
        if (_widgetTop == -1 || _widgetTopChange) {
          _widgetTopChange = false;
          RenderBox box = context.findRenderObject();
          Offset topLeftPosition = box.localToGlobal(Offset.zero);
          _widgetTop = topLeftPosition.dy.toInt();
        }
        int offset = details.globalPosition.dy.toInt() - _widgetTop;
        int index = _getIndex(offset);
        if (index != -1) {
          _lastIndex = index;
          _indexModel.position = index;
          _indexModel.tag = widget.data[index];
          _indexModel.isTouchDown = true;
          _triggerTouchEvent();
        }
      },
      onVerticalDragUpdate: (DragUpdateDetails details) {
        int offset = details.globalPosition.dy.toInt() - _widgetTop;
        int index = _getIndex(offset);
        if (index != -1 && _lastIndex != index) {
          _lastIndex = index;
          _indexModel.position = index;
          _indexModel.tag = widget.data[index];
          _indexModel.isTouchDown = true;
          _triggerTouchEvent();
        }
      },
      onVerticalDragEnd: (DragEndDetails details) {
        _indexModel.isTouchDown = false;
        _triggerTouchEvent();
        widget.onEnd();
      },
      onTapUp: (TapUpDetails details) {
        _indexModel.isTouchDown = false;
        _triggerTouchEvent();
        widget.onTapUp();
      },
      child: new Column(
        mainAxisSize: MainAxisSize.min,
        children: children,
      ),
    );
  }
}
